import 'package:flutter/material.dart';

/// 1.去除了IntrinsicWidth限制，添加了默认蒙版。
/// 2.简化position计算。
const double _kWindowScreenPadding = 0.001;
const double _kWindowCloseIntervalEnd = 2.0 / 3.0;

// 自定义弹窗控件：对弹窗内容进行再包装，添加长宽、动画等约束条件
class _PopupWindow<T> extends StatelessWidget {
  final PopupWinRoute<T> route;
  final String semanticLabel;

  const _PopupWindow({
    key,
    this.route,
    this.semanticLabel,
  });

  @override
  Widget build(BuildContext context) {
    const double length = 10.0;
    const double unit = 1.0 /
        (length + 1.5); // 1.0 for the width and 0.5 for the last item's fade.

    final CurveTween opacity =
        CurveTween(curve: const Interval(0.0, 1.0 / 3.0));
    final CurveTween width = CurveTween(curve: const Interval(0.0, unit));
    final CurveTween height =
        CurveTween(curve: const Interval(0.0, unit * length));

    final Widget child = SingleChildScrollView(
      child: route.child,
    );

    return AnimatedBuilder(
      animation: route.animation,
      builder: (BuildContext context, Widget child) {
        return Opacity(
          opacity: opacity.evaluate(route.animation),
          child: Align(
            alignment: AlignmentDirectional.topEnd,
            widthFactor: width.evaluate(route.animation),
            heightFactor: height.evaluate(route.animation),
            child: Semantics(
              scopesRoute: true,
              namesRoute: true,
              explicitChildNodes: true,
              label: semanticLabel,
              child: child,
            ),
          ),
        );
      },
      child: child,
    );
  }
}

// 自定义委托内容：子控件大小及其位置计算
class _PopupLayoutDelegate extends SingleChildLayoutDelegate {
  _PopupLayoutDelegate(this.position, this.textDirection);

  final RelativeRect position;
  final TextDirection textDirection;

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    // The menu can be at most the size of the overlay minus 8.0 pixels in each
    // direction.
    return BoxConstraints.loose(constraints.biggest -
        const Offset(
            _kWindowScreenPadding * 2.0, _kWindowScreenPadding * 2.0) as Size);
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    // size: The size of the overlay.
    // childSize: The size of the menu, when fully open, as determined by
    // getConstraintsForChild.

    // Find the ideal vertical position.
    double y = position.top;

    // Find the ideal horizontal position.
    double x;
    if (position.left > position.right) {
      // Menu button is closer to the right edge, so grow to the left, aligned to the right edge.
      x = size.width - position.right - childSize.width;
    } else if (position.left < position.right) {
      // Menu button is closer to the left edge, so grow to the right, aligned to the left edge.
      x = position.left;
    } else {
      // Menu button is equidistant from both edges, so grow in reading direction.
      switch (textDirection) {
        case TextDirection.rtl:
          x = size.width - position.right - childSize.width;
          break;
        case TextDirection.ltr:
          x = position.left;
          break;
      }
    }

    // Avoid going outside an area defined as the rectangle 8.0 pixels from the
    // edge of the screen in every direction.
    if (x < _kWindowScreenPadding) {
      x = _kWindowScreenPadding;
    } else if (x + childSize.width > size.width - _kWindowScreenPadding) {
      x = size.width - childSize.width - _kWindowScreenPadding;
    }

    if (y < _kWindowScreenPadding) {
      y = _kWindowScreenPadding;
    } else if (y + childSize.height > size.height - _kWindowScreenPadding) {
      y = size.height - childSize.height - _kWindowScreenPadding;
    }
    return Offset(x, y);
  }

  @override
  bool shouldRelayout(_PopupLayoutDelegate oldDelegate) {
    return position != oldDelegate.position;
  }
}

class PopupWinRoute<T> extends PopupRoute<T> {
  Widget child;
  RelativeRect position;
  bool isShowBg;
  String semanticLabel;
  final Duration _duration = Duration(milliseconds: 16);

  PopupWinRoute(this.child, {this.position, this.semanticLabel, this.isShowBg});

  @override
  // 弹出层遮罩颜色，该属性返回 null，即不设置遮罩颜色
  Color get barrierColor => null;

  @override
  // 是否允许点击遮罩关闭弹出层，该属性返回 true，即允许关闭
  bool get barrierDismissible => true;

  @override
  // 遮罩上显示的文本，该属性返回 null，即不显示文本
  String get barrierLabel => null;

  @override
  // 动画持续时间，返回 _duration 属性
  Duration get transitionDuration => _duration;

  @override
  Animation<double> createAnimation() {
    return CurvedAnimation(
        parent: super.createAnimation(),
        curve: Curves.linear,
        reverseCurve: const Interval(0.0, _kWindowCloseIntervalEnd));
  }

  Widget createMaterial(context, screenSize) {
    return Material(
      type: MaterialType.transparency,
      child: GestureDetector(
        // child: Container(
        //   width: double.infinity,
        //   height: double.infinity,
        //   color: Color(0x99000000),
        //   child: child,
        // ),
        child: Stack(
          children: [
            Container(
              height: screenSize.height,
              width: screenSize.width,
              color: Colors.black.withOpacity(0.3),
            ),
            SafeArea(
              child: Align(
                child: child,
              ),
            ),
          ],
        ),
        onTap: () {
          // print('----------');
          Navigator.pop(context);
        },
      ),
    );
  }

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    final Widget childWin = _PopupWindow<T>(
      route: this,
      semanticLabel: semanticLabel,
    );
    final screenSize = MediaQuery.of(context).size;

    return MediaQuery.removePadding(
      context: context,
      removeTop: true,
      removeBottom: true,
      removeLeft: true,
      removeRight: true,
      child: Builder(
        builder: (BuildContext context) {
          return GestureDetector(
            onTap: () => Navigator.pop(context),
            child: Material(
              type: MaterialType.transparency,
              child: Container(
                height: screenSize.height,
                width: screenSize.width,
                color: isShowBg ? const Color(0x99000000) : null,
                child: CustomSingleChildLayout(
                  delegate: _PopupLayoutDelegate(
                      position, Directionality.of(context)),
                  child: childWin,
                ),
              ),
            ),
          );
        },
      ),
    );

    // return MediaQuery.removePadding(
    //   context: context,
    //   removeTop: true,
    //   removeBottom: true,
    //   removeLeft: true,
    //   removeRight: true,
    //   child: Builder(
    //     builder: (BuildContext context) {
    //       return createMaterial(context, screenSize);
    //     },
    //   ),
    // );

    // return createMaterial(context, screenSize);
  }
}
